home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 …ember: Reference Library / Dev.CD Dec 00 RL Disk 1.toast / mac / Technical Documentation / Develop / develop Issue 23 / develop Issue 23 code / Multipane Dialogs Code.sea / Multipane Dialogs Code / MPDialogs.c / MPDialogs.c
Encoding:
C/C++ Source or Header  |  1995-10-17  |  39.1 KB  |  1,470 lines  |  [TEXT/MMCC]

  1. #include "MPDialogs.h"
  2. #include "Utilities.h"
  3. #include "ListControl.h"
  4. #include <Palettes.h>
  5. #include <Icons.h>
  6.  
  7. /********************************************************************************
  8.  *
  9.  * Main Multi-Pane Dialog Routines
  10.  *
  11.  ********************************************************************************/
  12.  
  13. DialogPtr OpenMPDialog(short resID, DefActionUPP defAction, ClickActionUPP clickProc,
  14.     EditActionUPP editAction, GroupActionUPP groupAction, Handle *theData)
  15. {
  16.     DialogPtr dlog;
  17.     GrafPtr oldPort;
  18.     MPDHdl dataH;
  19.     OSErr err = noErr;
  20.     short i, num, *dPtr, iType;
  21.     Str255 theStr;
  22.     Handle iHandle, dHandle = NULL;
  23.     Rect iRect;
  24.     ListHandle theList;
  25.     Cell theCell;
  26.     Boolean wasVisible;
  27.     
  28.     // One-time initialization of utility routines
  29.     if (!gInitMPDUtils) InitMPDUtils();
  30.     
  31.     // Open the MPD and allocate the MPD's MPDHdl
  32.     if (!(dlog = MyGetCenteredDialog(resID, nil, nil, (WindowPtr) -1L, &wasVisible))) {
  33.         return NULL;
  34.     }
  35.     if (!(dataH = (MPDHdl) NewHandle(sizeof(MPDRec)))) {
  36.         DisposeDialog(dlog);
  37.         return NULL;
  38.     }
  39.     MoveHHi((Handle) dataH);
  40.     SetWRefCon(dlog, (long) dataH);
  41.     (*dataH)->radio = NULL;
  42.     (*dataH)->currentPane = 1;
  43.     // Set up Action Procedures as requested
  44.     InstallAction(kItemAction, dlog, (UniversalProcPtr) clickProc);
  45.     InstallAction(kEditAction, dlog, (UniversalProcPtr) editAction);
  46.     InstallAction(kDefAction, dlog, (UniversalProcPtr) defAction);
  47.     InstallAction(kGroupAction, dlog, (UniversalProcPtr) groupAction);
  48.  
  49.     // Run though the dialog items and set user items to be the gray box
  50.     num = CountDITL(dlog);
  51.     (*dataH)->baseItems = num + 1;
  52.     for(i = kIconBox + 1; i <= num; i++) {
  53.         GetDialogItem(dlog, i, &iType, &iHandle, &iRect);
  54.         if ((iType & 0x7f) == userItem)
  55.             SetItemToGray(dlog, i);
  56.     }
  57.  
  58.     // Get ready for drawing
  59.     GetPort(&oldPort);
  60.     SetPort(dlog);
  61.     TextFont(applFont);
  62.     TextSize(9);
  63.     
  64.     // Fetch the DTL# resource, die if we can't
  65.     if (!(dHandle = GetResource(kDTL, resID))) goto die3;
  66.     HLock(dHandle);
  67.     
  68.     // Read in the pane IDs
  69.     dPtr = (short *) *dHandle;
  70.     num = (*dataH)->numPanes = *dPtr++;
  71.     (*dataH)->paneIDs = (short *) NewPtr(num * sizeof(short));
  72.     for(i=0; i<num; i++) {
  73.         (*dataH)->paneIDs[i] = *dPtr++;
  74.         dPtr += (*(char *) dPtr + sizeof(short)) >> 1;
  75.     }
  76.     (*dataH)->IconHandles = (Handle *) NewPtr(num * sizeof(Handle));
  77.  
  78.     // Set up the icon list control
  79.     GetDialogItem(dlog, kIconBox, &iType, &iHandle, &iRect);
  80.     if (!(theList = CLNew(rListCtl, true, &iRect, 0, 1, 60, iRect.right - iRect.left,
  81.             rIconDef, dlog, clVScroll | clActive | clKeyPos | clDrawIt))) goto die1;
  82.     (*theList)->selFlags |= lOnlyOne;
  83.     (*dataH)->theList = theList;
  84.     LAddRow(num, 0, theList);
  85.     
  86.     // Add the icons and label to the list
  87.     theCell.h = 0;
  88.     dPtr = ((short *) *dHandle) + 1;
  89.     for (theCell.v = 0; theCell.v < num; theCell.v++) {
  90.         dPtr++;
  91.         Pstrcpy(theStr, (ConstStr255Param) dPtr);
  92.         dPtr += (*(char *) dPtr + sizeof(short)) >> 1;
  93.         GetIconSuite(&(*dataH)->IconHandles[theCell.v], (*dataH)->paneIDs[theCell.v], svAllAvailableData);
  94.         LSetCell(&(*dataH)->IconHandles[theCell.v], sizeof(Handle), theCell, theList);
  95.         LAddToCell(theStr+1, theStr[0], theCell, theList);
  96.         
  97.         CreateRadioGroups(dlog, theCell.v);
  98.     }
  99.     ReleaseResource(dHandle);
  100.     dHandle = NULL;
  101.  
  102.     // Allocate the MPD and temporary data handles
  103.     if (!*theData) {
  104.         (*dataH)->theData = MPDTemplateFromDITL(dataH);
  105.         *theData = (*dataH)->theData;
  106.         *(long *) **theData = (*dataH)->currentPane;
  107.     } else {
  108.         (*dataH)->theData = *theData;
  109.         (*dataH)->currentPane = *(long *) **theData;
  110.     }
  111.     (*dataH)->tmpData = NewHandle(GetHandleSize((*dataH)->theData));
  112.     if (!(*dataH)->theData || !(*dataH)->tmpData) goto die2;
  113.  
  114.     // Display the first pane
  115.     InstallDITL(dlog, (*dataH)->currentPane);
  116.     HandleMPDAction(dlog, kR2TAction, 0);
  117.     HandleMPDAction(dlog, kT2PAction, (*dataH)->currentPane);
  118.     
  119.     if (theList) {
  120.         LSetDrawingMode(true, theList);
  121.         SetPt(&theCell, 0, (*dataH)->currentPane - 1);
  122.         LSetSelect(true, theCell, theList);
  123.     }
  124.     if (wasVisible) ShowWindow(dlog);
  125.     SetPort(oldPort);
  126.  
  127.     return dlog;
  128.     
  129.     die1:
  130.         DisposePtr((Ptr) (*dataH)->IconHandles);
  131.     die2:
  132.         DisposePtr((Ptr) (*dataH)->paneIDs);
  133.         if (dHandle) ReleaseResource(dHandle);
  134.     die3:
  135.         DisposeHandle((Handle) dataH);
  136.         DisposeDialog(dlog);
  137.         return NULL;
  138. }
  139.  
  140. Handle GetMPDialogHandle(short resID, EditActionUPP editAction, GroupActionUPP groupAction)
  141. {
  142.     DialogPtr dlog;
  143.     MPDHdl dataH;
  144.     OSErr err = noErr;
  145.     short i, num, *dPtr;
  146.     Handle dHandle = NULL, retHandle = NULL;
  147.     Boolean wasVisible;
  148.     RadioGroupPtr next, group;
  149.     
  150.     // One-time initialization of utility routines
  151.     if (!gInitMPDUtils) InitMPDUtils();
  152.     
  153.     // Open the MPD and allocate the MPD's MPDHdl
  154.     if (!(dlog = MyGetCenteredDialog(resID, nil, nil, (WindowPtr) -1L, &wasVisible))) {
  155.         return NULL;
  156.     }
  157.     if (!(dataH = (MPDHdl) NewHandle(sizeof(MPDRec)))) {
  158.         DisposeDialog(dlog);
  159.         return NULL;
  160.     }
  161.     MoveHHi((Handle) dataH);
  162.     (*dataH)->radio = NULL;
  163.     (*dataH)->currentPane = 1;
  164.     (*dataH)->IconHandles = NULL;
  165.     (*dataH)->theList = NULL;
  166.     (*dataH)->tmpData = NULL;
  167.     SetWRefCon(dlog, (long) dataH);
  168.  
  169.     // Set up Action Procedures as requested, but only the Edit and Group can
  170.     // affect the data handle
  171.     InstallAction(kItemAction, dlog, (UniversalProcPtr) nil);
  172.     InstallAction(kEditAction, dlog, (UniversalProcPtr) editAction);
  173.     InstallAction(kDefAction, dlog, (UniversalProcPtr) nil);
  174.     InstallAction(kGroupAction, dlog, (UniversalProcPtr) groupAction);
  175.  
  176.     num = CountDITL(dlog);
  177.     (*dataH)->baseItems = num + 1;
  178.  
  179.     // Fetch the DTL# resource, die if we can't
  180.     if (!(dHandle = GetResource(kDTL, resID))) goto die2;
  181.     HLock(dHandle);
  182.     
  183.     // Read in the pane IDs
  184.     dPtr = (short *) *dHandle;
  185.     num = (*dataH)->numPanes = *dPtr++;
  186.     (*dataH)->paneIDs = (short *) NewPtr(num * sizeof(short));
  187.     for(i=0; i<num; i++) {
  188.         (*dataH)->paneIDs[i] = *dPtr++;
  189.         dPtr += (*(char *) dPtr + sizeof(short)) >> 1;
  190.     }
  191.  
  192.     // Create the Radio Groups
  193.     for (i = 0; i < num; i++) {
  194.         CreateRadioGroups(dlog, i);
  195.     }
  196.  
  197.     // Allocate the MPD and temporary data handles
  198.     (*dataH)->theData = MPDTemplateFromDITL(dataH);
  199.     *(long *) *(*dataH)->theData = (*dataH)->currentPane;
  200.     if (!(*dataH)->theData) goto die1;
  201.     retHandle = (*dataH)->theData;
  202.     
  203.     die1:
  204.         DisposePtr((Ptr) (*dataH)->paneIDs);
  205.         if (dHandle) ReleaseResource(dHandle);
  206.         for(group=(*dataH)->radio; group; group=next) {
  207.             next = group->next;
  208.             DisposePtr((Ptr) group);
  209.         }
  210.     die2:
  211.         DisposeHandle((Handle) dataH);
  212.         DisposeDialog(dlog);
  213.         return retHandle;
  214. }
  215.  
  216. void CloseMPDialog(DialogPtr *dlog)
  217. {
  218.     MPDHdl dataH;
  219.     short i;
  220.     RadioGroupPtr next, group;
  221.     
  222.     dataH = (MPDHdl) GetWRefCon(*dlog);
  223.     // Preserve last open pane
  224.     *(long *) *(*dataH)->theData = (*dataH)->currentPane;
  225.     // Dispose of the icon suites
  226.     for(i = 0; i < (*dataH)->numPanes; i++)
  227.         DisposeIconSuite((*dataH)->IconHandles[i], true);
  228.     DisposePtr((Ptr) (*dataH)->IconHandles);
  229.     // Dispose of the radio group storage
  230.     for(group=(*dataH)->radio; group; group=next) {
  231.         next = group->next;
  232.         DisposePtr((Ptr) group);
  233.     }
  234.     // Dispose of everything else
  235.     DisposePtr((Ptr) (*dataH)->paneIDs);
  236.     DisposeHandle((*dataH)->tmpData);
  237.     DisposeHandle((Handle) dataH);
  238.     DisposeDialog(*dlog);
  239.     // Tell caller we closed the MPD
  240.     *dlog = NULL;
  241. }
  242.  
  243. short DoMPDialogEvent(DialogPtr *dlog, EventRecord *theEvent, short *result)
  244. {
  245.     short itemHit = 0, dblClick, part;
  246.     DialogPtr dptr;
  247.     GrafPtr oldPort;
  248.     WindowPtr window, fwin = FrontWindow();
  249.     MPDHdl dataH;
  250.     Cell theCell;
  251.     
  252.     *result = kNotClosed; // Not closed as a result of this event
  253.     if (!*dlog) return kNotHandled;
  254.     dataH = (MPDHdl) GetWRefCon(*dlog);
  255.  
  256.     GetPort(&oldPort);
  257.     SetPort(*dlog);
  258.  
  259.     // Handle events only for this MPD
  260.     switch (theEvent->what) {
  261.         case 0:
  262.             break;
  263.         case mouseDown:
  264.             part = FindWindow(theEvent->where, &window);
  265.             if (window != *dlog) goto exitNotHandled;
  266.             switch (part) {
  267.                 case inDrag:
  268.                     DragWindow(window, theEvent->where, &qd.screenBits.bounds);
  269.                     goto exitHandled;
  270.                 case inGoAway:
  271.                     if (TrackGoAway(window, theEvent->where)) {
  272.                         CloseMPDialog(dlog);
  273.                         goto exitHandled;
  274.                     }
  275.                     break;
  276.             }
  277.             if (CLClick(*dlog, theEvent, &dblClick)) itemHit = kIconBox;
  278.             break;
  279.         case keyDown:
  280.         case autoKey:
  281.             if (fwin != *dlog) goto exitNotHandled;
  282.             switch (theEvent->message & charCodeMask) {
  283. #ifdef SNARF_LR_ARROWS
  284.                 case kLeftArrow:
  285.                     theEvent->message = kUpArrow;
  286.                     goto doit;
  287.                 case kRightArrow:
  288.                     theEvent->message = kDownArrow;
  289.                     goto doit;
  290. #else
  291.                 case kLeftArrow:
  292.                     if (NumberOfEditFields(fwin) != 0) break;
  293.                     theEvent->message = kUpArrow;
  294.                     goto doit;
  295.                 case kRightArrow:
  296.                     if (NumberOfEditFields(fwin) != 0) break;
  297.                     theEvent->message = kDownArrow;
  298.                     goto doit;
  299. #endif
  300.                 case '\t':
  301.                     // Don't allow TAB to change panes if multiple edit fileds are on the pane
  302.                     if (MultipleEditFields(*dlog)) break;
  303.                     theEvent->message = (theEvent->modifiers & shiftKey) ? kUpArrow : kDownArrow;
  304.                 case kUpArrow:
  305.                 case kDownArrow:
  306.                 doit:
  307.                     if (CLKey(*dlog, theEvent)) itemHit = kIconBox;
  308.                     break;
  309.             }
  310.             break;
  311.         case activateEvt:
  312.         case updateEvt:
  313.             if ((WindowPtr) theEvent->message != *dlog) goto exitNotHandled;
  314.             if (theEvent->what == activateEvt)
  315.                 LActivate(theEvent->modifiers & activeFlag, (*dataH)->theList);
  316.             break;
  317.         case osEvt:
  318.             if ((theEvent->message & osEvtMessageMask) == (suspendResumeMessage << 24))
  319.                 LActivate((theEvent->message & resumeFlag) != 0, (*dataH)->theList);
  320.             break;
  321.         default:
  322.             goto exitNotHandled;
  323.     }
  324.  
  325.     // After handling non-dialog window events, try for the dialog events including
  326.     // key equivalents for both the main dialog and the current pane.
  327.     if (!itemHit && !keyAltFilter(*dlog, kKeyStrings, 0, theEvent, &itemHit) &&
  328.                 !keyAltFilter(*dlog, (*dataH)->baseItems, (*dataH)->baseItems-1, theEvent, &itemHit)) {
  329.         if (!IsDialogEvent(theEvent)) goto exitNotHandled;
  330.         if (!DialogSelect(theEvent,&dptr,&itemHit)) {
  331.             if (theEvent->what == mouseDown) goto exitHandled;
  332.             goto exitNotHandled; // Not for us
  333.         } else if (!itemHit) {
  334.             goto exitHandled;    // For us, but not exciting
  335.         } else {                // Handle revert when EditText fields change
  336.             Handle iHandle;
  337.             short iType;
  338.             Rect iRect;
  339.             
  340.             GetDialogItem(*dlog, itemHit, &iType, &iHandle, &iRect);
  341.             if (iType == editText) {
  342.                 if (theEvent->what == keyDown && (theEvent->message & charCodeMask) >= ' ') {
  343.                      (*dataH)->paneDirty = true;
  344.                      AbleDItem(*dlog, kBRevert, true);
  345.                 }
  346.                 goto exitHandled;
  347.             }
  348.         }
  349.     }
  350.  
  351.     // Did something interesting happen?
  352.     switch (itemHit) {
  353.         case 0:
  354.             break;
  355.         case kBOk:
  356.             // Save the values of the controls and retain MPD changes
  357.             // The dialog can't be Oked if a validation error is returned
  358.             if (HandleMPDAction(*dlog, kP2TAction, (*dataH)->currentPane))
  359.                 HandleMPDAction(*dlog, kT2RAction, 0);
  360.             else break;
  361.             CloseMPDialog(dlog);
  362.             *result = kOKClosed;
  363.             break;
  364.         case kBCancel:
  365.             // Close the dialog if Oked or Canceled
  366.             CloseMPDialog(dlog);
  367.             *result = kCancelClosed;
  368.             break;
  369.         case kBRevert:
  370.             // Restore previous settings
  371.             HandleMPDAction(*dlog, kT2PAction, (*dataH)->currentPane);
  372.              (*dataH)->paneDirty = false;
  373.              AbleDItem(*dlog, kBRevert, false);
  374.             break;
  375.         case kBFactory:
  376.             // Restore factory defaults
  377.             SetFactoryDefault(*dlog, (*dataH)->currentPane);
  378.              (*dataH)->paneDirty = true;
  379.              AbleDItem(*dlog, kBRevert, true);
  380.             break;
  381.         case kIconBox:
  382.             // Has the pane changed?
  383.             if (!(*dataH)->theList) goto exitHandled;
  384.             theCell.h = theCell.v = 0;
  385.             if (LGetSelect(true, &theCell, (*dataH)->theList)) {
  386.                 theCell.v++;
  387.                 if (theCell.v != (*dataH)->currentPane) {
  388.                     if (!HandleMPDAction(*dlog, kP2TAction, (*dataH)->currentPane)) {
  389.                         // We can't change the pane now
  390.                         theCell.v--;
  391.                         LSetSelect(false, theCell, (*dataH)->theList);
  392.                         theCell.v = (*dataH)->currentPane - 1;
  393.                         LSetSelect(true, theCell, (*dataH)->theList);
  394.                         goto exitHandled;
  395.                     }
  396.                     // Change the pane
  397.                     (*dataH)->currentPane = theCell.v;
  398.                     InstallDITL(*dlog, theCell.v);
  399.                     HandleMPDAction(*dlog, kT2PAction, theCell.v);
  400.                  }
  401.              }
  402.              break;
  403.          default:
  404.              // A control was clicked
  405.              CallClickActionProc((*dataH)->ClickAction, kClickAction, *dlog, (*dataH)->currentPane, itemHit);
  406.              if (!(*dataH)->paneDirty) {
  407.                  (*dataH)->paneDirty = true;
  408.                  AbleDItem(*dlog, kBRevert, true);
  409.              }
  410.              break;
  411.     }
  412.  
  413.     exitHandled:
  414.         SetPort(oldPort);
  415.         return kHandled;
  416.  
  417.     exitNotHandled:
  418.         SetPort(oldPort);
  419.         return kNotHandled;
  420. }
  421.  
  422. short NumberOfEditFields(DialogPtr dlog)
  423. {
  424.     MPDHdl dataH;
  425.     short numItems, i, iType, numEdits = 0;
  426.     Handle iHandle;
  427.     Rect iRect;
  428.     
  429.     if (!dlog) return false;
  430.     dataH = (MPDHdl) GetWRefCon(dlog);
  431.     numItems = CountDITL(dlog);
  432.     
  433.     for(i=(*dataH)->baseItems; i<=numItems; i++) {
  434.         GetDialogItem(dlog, i, &iType, &iHandle, &iRect);
  435.         if (iType == editText) numEdits++;
  436.     }
  437.     return(numEdits);
  438. }
  439.  
  440. Boolean MultipleEditFields(DialogPtr dlog)
  441. {
  442.     return (NumberOfEditFields(dlog) > 1);
  443. }
  444.  
  445. // UniversalProcPtr stuff for default Action Procedures
  446. #if USESROUTINEDESCRIPTORS
  447. RoutineDescriptor gClickActionRoutine = BUILD_ROUTINE_DESCRIPTOR(kClickProcInfo, DefaultClickAction);
  448. RoutineDescriptor gEditActionRoutine = BUILD_ROUTINE_DESCRIPTOR(kEditProcInfo, DefaultEditAction);
  449. RoutineDescriptor gGroupActionRoutine = BUILD_ROUTINE_DESCRIPTOR(kGroupProcInfo, DefaultGroupAction);
  450. RoutineDescriptor gDefActionRoutine = BUILD_ROUTINE_DESCRIPTOR(kDefProcInfo, DefaultAction);
  451. ClickActionUPP gClickActionProc = &gClickActionRoutine;
  452. EditActionUPP gEditActionProc = &gEditActionRoutine;
  453. GroupActionUPP gGroupActionProc = &gGroupActionRoutine;
  454. DefActionUPP gDefActionProc = &gDefActionRoutine;
  455. #else
  456. ClickActionUPP gClickActionProc = (ClickActionUPP) DefaultClickAction;
  457. EditActionUPP gEditActionProc = (EditActionUPP) DefaultEditAction;
  458. GroupActionUPP gGroupActionProc = (GroupActionUPP) DefaultGroupAction;
  459. DefActionUPP gDefActionProc = (DefActionUPP) DefaultAction;
  460. #endif
  461.  
  462. short InstallAction(short aType, DialogPtr dlog, UniversalProcPtr actionProc)
  463. {
  464.     MPDHdl dataH;
  465.     
  466.     dataH = (MPDHdl) GetWRefCon(dlog);
  467.     switch (aType) {
  468.         case kItemAction:
  469.             (*dataH)->ClickAction = actionProc ? (ClickActionUPP) actionProc : gClickActionProc;
  470.             break;
  471.         case kEditAction:
  472.             (*dataH)->EditAction = actionProc ? (EditActionUPP) actionProc : gEditActionProc;
  473.             break;
  474.         case kGroupAction:
  475.             (*dataH)->GroupAction = actionProc ? (GroupActionUPP) actionProc : gGroupActionProc;
  476.             break;
  477.         case kDefAction:
  478.             (*dataH)->DefAction = actionProc ? (DefActionUPP) actionProc : gDefActionProc;
  479.             break;
  480.         default:
  481.             return kNotHandled;
  482.     }
  483.     return kHandled;
  484. }
  485.  
  486. short RemoveAction(short aType, DialogPtr dlog)
  487. {
  488.     return InstallAction(aType, dlog, NULL);
  489. }
  490.  
  491. /********************************************************************************
  492.  *
  493.  * Multi-Pane Dialog Data Access Routines
  494.  *
  495.  ********************************************************************************/
  496.  
  497. short GetMPDItem(Handle theData, short pane, short item, Ptr ptr, short len)
  498. {
  499.     Ptr hPtr;
  500.     short i;
  501.  
  502.     if (!theData) return keNullData;
  503.     hPtr = *theData + sizeof(long);
  504.     
  505.     // Find the correct pane…
  506.     for(i=1; i<pane; i++) {
  507.         hPtr += 4;
  508.         if (*(long *) hPtr == 0L) return keBadPane;
  509.     }
  510.     hPtr = *theData + sizeof(long) + *(long *) hPtr;
  511.     
  512.     // Find the correct item…
  513.     for(item--;item; item--) {
  514.         hPtr += (*(short *) hPtr) + sizeof(short);
  515.         if (!*(short *) hPtr) return keBadItem;
  516.     }
  517.     
  518.     // Get the value
  519.     if (len != *(short *) hPtr) return keWrongSize;
  520.     BlockMove(hPtr+sizeof(short), ptr, *(short *) hPtr);
  521.     return noErr;
  522. }
  523.  
  524. short SetMPDItem(Handle theData, short pane, short item, Ptr ptr, short len)
  525. {
  526.     Ptr hPtr;
  527.     short i;
  528.  
  529.     if (!theData) return keNullData;
  530.     HLock(theData);
  531.     hPtr = *theData + sizeof(long);
  532.     
  533.     // Find the correct pane…
  534.     for(i=1; i<pane; i++) {
  535.         hPtr += 4;
  536.         if (*(long *) hPtr == 0L) return keBadPane;
  537.     }
  538.     hPtr = *theData + sizeof(long) + *(long *) hPtr;
  539.     
  540.     // Find the correct item…
  541.     for(item--;item; item--) {
  542.         hPtr += (*(short *) hPtr) + sizeof(short);
  543.         if (!*(short *) hPtr) return keBadItem;
  544.     }
  545.  
  546.     // Set the value
  547.     if (len != *(short *) hPtr) return keWrongSize;
  548.     BlockMove(ptr, hPtr+sizeof(short), *(short *) hPtr);
  549.     return noErr;
  550. }
  551.  
  552. /********************************************************************************
  553.  *
  554.  * Internal Multi-Pane Dialog Routines
  555.  *
  556.  ********************************************************************************/
  557.  
  558. void InstallDITL(DialogPtr dlog, short pane)
  559. {
  560.     MPDHdl dataH;
  561.     Handle theDITL, iHandle;
  562.     short i, num, iType;
  563.     Rect iRect;
  564.     
  565.     dataH = (MPDHdl) GetWRefCon(dlog);
  566.     // Pane is now no longer dirty
  567.      (*dataH)->paneDirty = false;
  568.      AbleDItem(dlog, kBRevert, false);
  569.     
  570.     // Remove old pane
  571.     i = CountDITL(dlog) - (*dataH)->baseItems + 1;
  572.     ShortenDITL(dlog, i);
  573.  
  574.     SetPort(dlog);
  575.     TextFont(geneva);
  576.     TextSize(9);
  577.     TextFace(0);
  578.     
  579.     // Install new one
  580.     theDITL = GetResource('DITL', (*dataH)->paneIDs[pane-1]);
  581.     if (!theDITL) return;
  582.     AppendDITL(dlog, theDITL, overlayDITL);
  583.     ReleaseResource(theDITL);
  584.     
  585.     // Set all user items to be the gray box
  586.     num = CountDITL(dlog);
  587.     for(i=(*dataH)->baseItems; i<=num; i++) {
  588.         GetDialogItem(dlog, i, &iType, &iHandle, &iRect);
  589.         if ((iType & 0x7f) == userItem)
  590.             SetItemToGray(dlog, i);
  591.     }
  592. }
  593.  
  594. Handle MPDTemplateFromDITL(MPDHdl dataH)
  595. {
  596.     short ditl, i, dcount, iType, pseudoItem = 1;
  597.     short num = (*dataH)->numPanes, *DITList = (*dataH)->paneIDs;
  598.     Handle h, iHandle, theData;
  599.     DialogPtr dptr;
  600.     Rect wRect, iRect;
  601.     long hSize, tSize;
  602.     DialogRecord storage;
  603.     
  604.     hSize = sizeof(long) * (num + 1);
  605.     theData = NewHandle(hSize);
  606.     MoveHHi(theData);
  607.     SetRect(&wRect, 0, 0, 50, 50);
  608.     
  609.     // Process all the panes…
  610.     for(ditl=0; ditl<num; ditl++) {
  611.         // Load the pane's DITL so we can run through it, without knowing it's structure.
  612.         ((long *) *theData)[ditl] = hSize;
  613.         h = GetResource('DITL', DITList[ditl]);
  614.         DetachResource(h);
  615.         if (!h) continue; // Oops!
  616.         dptr = NewDialog(&storage, &wRect, "\p", false, dBoxProc, (WindowPtr) -1, false, 0, h);
  617.         if (!dptr) continue; // Oops!
  618.         pseudoItem = 1;
  619.         
  620.         // Process each item in the pane…
  621.         dcount = CountDITL(dptr);
  622.         for(i=1; i<=dcount; i++) {
  623.             GetDialogItem(dptr, i, &iType, &iHandle, &iRect);
  624.             switch(iType & 0x7f) {
  625.                 case 4: // Button
  626.                 case 5: // Check box
  627.                 case 7: // Control
  628.                     SetHandleSize(theData, hSize+4);
  629.                     if (MemError()) goto error;
  630.                     *(short *) ((*theData) + hSize) = sizeof(short);
  631.                     hSize += sizeof(short);
  632.                     HLock(theData);
  633.                     CallDefActionProc((*dataH)->DefAction ,(*theData) + hSize, sizeof(short),
  634.                         iType, ditl+1, pseudoItem);
  635.                     HUnlock(theData);
  636.                     hSize += sizeof(short);
  637.                     pseudoItem++;
  638.                     break;
  639.                 case 6: // Radio Button
  640.                     tSize = GetRadioMPDSize((*dataH)->radio, ditl+1, i);
  641.                     // If the Radio Button is not part of a radio group,
  642.                     // handle it as a check box
  643.                     if (tSize) {
  644.                         SetHandleSize(theData, hSize+sizeof(short)+tSize);
  645.                         if (MemError()) goto error;
  646.                         *(short *) ((*theData) + hSize) = tSize;
  647.                         hSize += sizeof(short);
  648.                         HLock(theData);
  649.                         CallDefActionProc((*dataH)->DefAction, (*theData) + hSize, sizeof(short),
  650.                             iType, ditl+1, pseudoItem);
  651.                         HUnlock(theData);
  652.                         hSize += tSize;
  653.                         pseudoItem++;
  654.                     }
  655.                     break;
  656.                 case editText: // TextEdit field
  657.                     tSize = CallEditActionProc((*dataH)->EditAction,
  658.                             kCalcAction, NULL, iHandle, ditl+1, pseudoItem);
  659.                     SetHandleSize(theData, hSize+sizeof(short)+tSize);
  660.                     if (MemError()) goto error;
  661.                     *(short *) ((*theData) + hSize) = tSize;
  662.                     hSize += sizeof(short);
  663.                     HLock(theData);
  664.                     CallEditActionProc((*dataH)->EditAction,
  665.                             kInitAction, (*theData) + hSize, iHandle, ditl+1, pseudoItem);
  666.                     HUnlock(theData);
  667.                     hSize += tSize;
  668.                     pseudoItem++;
  669.                     break;
  670.                 default:
  671.                     break;
  672.             }
  673.         }
  674.  
  675.         // When done with all the normal items, do the radio grouped items
  676.         HLock(theData);
  677.         tSize = DoGroupAction(kCalcAction, (WindowPtr) dataH, NULL, ditl+1, NULL);
  678.         HUnlock(theData);
  679.         if (tSize) {
  680.             SetHandleSize(theData, hSize+tSize);
  681.             if (MemError()) goto error;
  682.             DoGroupAction(kInitAction, (WindowPtr) dataH, *theData+hSize, ditl+1, &pseudoItem);
  683.             hSize += tSize;
  684.         }
  685.         SetHandleSize(theData, hSize+sizeof(short));
  686.         if (MemError()) goto error;
  687.         *(short *) &(*theData)[hSize] = 0;
  688.         hSize += sizeof(short);
  689.         CloseDialog(dptr);
  690.     }
  691.     ((long *) *theData)[ditl] = 0L;
  692.     if (hSize != GetHandleSize(theData)) SysBeep(3);
  693.     SetHandleSize(theData, hSize + sizeof(long));
  694.     if (MemError()) goto error;
  695.     BlockMove(*theData, *theData + sizeof(long), hSize);
  696.     *(long *) *theData = 1;
  697.     return MemError() ? NULL : theData;
  698.     
  699.     error:
  700.         DisposeHandle(theData);
  701.         if (dptr) CloseDialog(dptr);
  702.         return NULL;
  703. }
  704.  
  705. short CreateMPDRadioGroup(DialogPtr dlog, short pane, short *itemList, short itemNum)
  706. {
  707.     MPDHdl dataH;
  708.     RadioGroupPtr group;
  709.     
  710.     dataH = (MPDHdl) GetWRefCon(dlog);
  711.     group = (RadioGroupPtr) NewPtr(sizeof(RadioGroup) + itemNum * sizeof(short));
  712.     if (!group) return dsMemFullErr;
  713.     BlockMove(itemList, &group->items, itemNum * sizeof(short));
  714.     group->num = itemNum;
  715.     group->pane = pane;
  716.     group->next = (*dataH)->radio;
  717.     (*dataH)->radio = group;
  718.     return noErr;
  719. }
  720.  
  721. void CreateRadioGroups(DialogPtr dlog, short pane)
  722. {
  723.     MPDHdl dataH;
  724.     Handle h;
  725.     short g, numGroups, numItems;
  726.     short *p = NULL;
  727.  
  728.     dataH = (MPDHdl) GetWRefCon(dlog);
  729.     
  730.     if (!(h = GetResource(kGROUP, (*dataH)->paneIDs[pane]))) return;
  731.     MoveHHi(h);
  732.     HLock(h);
  733.     p = (short *) *h;
  734.     numGroups = *p++;
  735.     
  736.     for(g=0; g<numGroups; g++) {
  737.         numItems = *p++;
  738.         CreateMPDRadioGroup(dlog, pane+1, p, numItems);
  739.         p += numItems;
  740.     }
  741.     
  742.     HUnlock(h);
  743.     ReleaseResource(h);
  744. }
  745.  
  746. void SetFactoryDefault(DialogPtr dlog, short pane)
  747. {
  748.     short i, iType, tSize, hilited = false, val, pseudoItem = 1;
  749.     Handle iHandle;
  750.     Rect iRect;
  751.     MPDHdl dataH;
  752.     RadioGroupPtr radio;
  753.     Ptr tmpPtr;
  754.     
  755.     dataH = (MPDHdl) GetWRefCon(dlog);
  756.     HLock((*dataH)->theData);
  757.     radio = (*dataH)->radio;
  758.  
  759.     for(i=(*dataH)->baseItems; i<=CountDITL(dlog); i++) {
  760.         GetDialogItem(dlog, i, &iType, &iHandle, &iRect);
  761.         switch(iType & 0x7f) {
  762.             case 4: // Button
  763.             case 5: // Check box
  764.             case 7: // Control
  765.                 CallDefActionProc((*dataH)->DefAction, (Ptr) &val, sizeof(short), iType,
  766.                     pane, pseudoItem);
  767.                 SetControlValue((ControlHandle) iHandle, val);
  768.                 pseudoItem++;
  769.                 break;
  770.             case 6: // Radio Button
  771.                 if (tSize = GetRadioMPDSize(radio, pane, i - (*dataH)->baseItems + 1)) {
  772.                     CallDefActionProc((*dataH)->DefAction, (Ptr) &val, sizeof(short),
  773.                         iType, pane, pseudoItem);
  774.                     SetControlValue((ControlHandle) iHandle, val);
  775.                     pseudoItem++;
  776.                 }
  777.                 break;
  778.             case editText:
  779.                 // Allocate a temporart pointer to hold the factory value, get the
  780.                 // default value, and finally set the control.
  781.                 tSize = CallEditActionProc((*dataH)->EditAction, 
  782.                         kCalcAction, NULL, iHandle, pane, pseudoItem);
  783.                 if (!(tmpPtr = NewPtr(tSize))) break;
  784.                 CallEditActionProc((*dataH)->EditAction,
  785.                         kInitAction, tmpPtr, iHandle, pane, pseudoItem);
  786.                 CallEditActionProc((*dataH)->EditAction,
  787.                         kT2PAction, tmpPtr, iHandle, pane, pseudoItem);
  788.                 DisposePtr(tmpPtr);
  789.                 // Hilite first EditText field in the dialog
  790.                 if (!hilited) {
  791.                     SelectDialogItemText(dlog, i, 0, 32768);
  792.                     hilited = true;
  793.                 }
  794.                 pseudoItem++;
  795.                 break;
  796.             default:
  797.                 break;
  798.         }
  799.     }
  800.     
  801.     // After handling the normal controls, handle the radio grouped controls
  802.     tSize = DoGroupAction(kCalcAction, (WindowPtr) dataH, NULL, pane, NULL);
  803.     if (tSize) {
  804.         if (!(tmpPtr = NewPtr(tSize))) return;
  805.         DoGroupAction(kInitAction, (WindowPtr) dataH, tmpPtr, pane, &val);
  806.         DoGroupAction(kT2PAction, dlog, tmpPtr, pane, &pseudoItem);
  807.         DisposePtr(tmpPtr);
  808.     }
  809.     
  810.     HUnlock((*dataH)->theData);
  811.     return;
  812. }
  813.  
  814. void ToggleGroup(DialogPtr dlog, RadioGroupPtr group, short item)
  815. {
  816.     MPDHdl dataH;
  817.     short i;
  818.  
  819.     dataH = (MPDHdl) GetWRefCon(dlog);
  820.     for(i=0; i<group->num; i++) {
  821.         SetCheckOrRadioButton(dlog, group->items[i] + (*dataH)->baseItems - 1, group->items[i] == item);
  822.     }
  823. }
  824.  
  825. short GetRadioMPDSize(RadioGroupPtr radio, short pane, short item)
  826. {
  827.     RadioGroupPtr group;
  828.     short i, ret = sizeof(short);
  829.     
  830.     // If the control is a member of a radio group, return zero, else return sizeof(short).
  831.     for(group=radio; group; group=group->next) {
  832.         if (group->pane == pane)
  833.             for(i=0; i<group->num; i++) {
  834.                 if (group->items[i] == item) ret = 0;
  835.             }
  836.     }
  837.     return ret;
  838. }
  839.  
  840. /********************************************************************************
  841.  *
  842.  * Internal Multi-Pane Dialog Action Procedures
  843.  *
  844.  ********************************************************************************/
  845.  
  846. short HandleMPDAction(DialogPtr dlog, short message, short pane)
  847. {
  848.     MPDHdl dataH;
  849.     long hSize;
  850.     
  851.     dataH = (MPDHdl) GetWRefCon(dlog);
  852.     hSize = GetHandleSize((*dataH)->theData);
  853.     switch (message) {
  854.         case kR2TAction:    // Transfer real to temporary
  855.             HLock((*dataH)->theData);
  856.             HLock((*dataH)->tmpData);
  857.             BlockMove(*(*dataH)->theData, *(*dataH)->tmpData, hSize);
  858.             HUnlock((*dataH)->theData);
  859.             HUnlock((*dataH)->tmpData);
  860.             break;
  861.         case kP2TAction:    // Transfer controls to temporary
  862.             return P2TMPDAction(dlog, pane);
  863.         case kT2PAction:    // Transfer temporary to controls
  864.             return T2PMPDAction(dlog, pane);
  865.         case kT2RAction:    // Transfer temporary to real
  866.             HLock((*dataH)->theData);
  867.             HLock((*dataH)->tmpData);
  868.             BlockMove(*(*dataH)->tmpData, *(*dataH)->theData, hSize);
  869.             HUnlock((*dataH)->theData);
  870.             HUnlock((*dataH)->tmpData);
  871.             break;
  872.         default:
  873.             return kNotHandled;
  874.     }
  875.     return kHandled;
  876. }
  877.  
  878. short P2TMPDAction(DialogPtr dlog, short pane)
  879. {
  880.     short i, iType, tSize, pseudoItem = 1, sSize;
  881.     Handle iHandle;
  882.     Rect iRect;
  883.     MPDHdl dataH;
  884.     Ptr hPtr;
  885.     RadioGroupPtr radio;
  886.     
  887.     dataH = (MPDHdl) GetWRefCon(dlog);
  888.     HLock((*dataH)->tmpData);
  889.     hPtr = *(*dataH)->tmpData + sizeof(long) + ((long *) *(*dataH)->tmpData)[pane];
  890.     radio = (*dataH)->radio;
  891.  
  892.     // Validate the pane, returning false if it doesn't
  893.     for(i=(*dataH)->baseItems; i<=CountDITL(dlog); i++) {
  894.         GetDialogItem(dlog, i, &iType, &iHandle, &iRect);
  895.         // Abort transfer if something's gone awry…
  896.          if (CallClickActionProc((*dataH)->ClickAction, kValidateAction, dlog, pane, i))
  897.              return false;
  898.     }
  899.     
  900.     // Store the control values into memory
  901.     for(i=(*dataH)->baseItems; i<=CountDITL(dlog); i++) {
  902.         GetDialogItem(dlog, i, &iType, &iHandle, &iRect);
  903.          
  904.         switch(iType & 0x7f) {
  905.             case 4: // Button
  906.             case 5: // Check box
  907.             case 7: // Control
  908.                 sSize = *(short *) hPtr;
  909.                 hPtr += sizeof(short);
  910.                 *(short *) hPtr = GetControlValue((ControlHandle) iHandle);
  911.                 hPtr += sSize;
  912.                 pseudoItem++;
  913.                 break;
  914.             case 6: // Radio Button
  915.                 if (tSize = GetRadioMPDSize(radio, pane, i - (*dataH)->baseItems + 1)) {
  916.                     sSize = *(short *) hPtr;
  917.                     hPtr += sizeof(short);
  918.                     *(short *) hPtr = GetControlValue((ControlHandle) iHandle);
  919.                     hPtr += sSize;
  920.                     pseudoItem++;
  921.                 }
  922.                 break;
  923.             case editText:
  924.                 sSize = *(short *) hPtr;
  925.                 hPtr += sizeof(short);
  926. #ifdef INC_TOO_MUCH
  927.                 hPtr += CallEditActionProc((*dataH)->EditAction,
  928.                         kP2TAction, hPtr, iHandle, pane, pseudoItem);
  929. #else
  930.                 CallEditActionProc((*dataH)->EditAction,
  931.                         kP2TAction, hPtr, iHandle, pane, pseudoItem);
  932. #endif
  933.                 hPtr += sSize;
  934.                 pseudoItem++;
  935.                 break;
  936.             default:
  937.                 break;
  938.         }
  939.     }
  940.     hPtr += DoGroupAction(kP2TAction, dlog, hPtr, pane, &pseudoItem);
  941.     HUnlock((*dataH)->theData);
  942.     return true;
  943. }
  944.  
  945. short T2PMPDAction(DialogPtr dlog, short pane)
  946. {
  947.     short i, iType, tSize, hilited = false, pseudoItem = 1, sSize;
  948.     Handle iHandle;
  949.     Rect iRect;
  950.     MPDHdl dataH;
  951.     Ptr hPtr;
  952.     RadioGroupPtr radio;
  953.     
  954.     dataH = (MPDHdl) GetWRefCon(dlog);
  955.     HLock((*dataH)->tmpData);
  956.     hPtr = *(*dataH)->tmpData + sizeof(long) + ((long *) *(*dataH)->tmpData)[pane];
  957.     radio = (*dataH)->radio;
  958.  
  959.     // Set the controls based on the values in memory
  960.     for(i=(*dataH)->baseItems; i<=CountDITL(dlog); i++) {
  961.         GetDialogItem(dlog, i, &iType, &iHandle, &iRect);
  962.         switch(iType & 0x7f) {
  963.             case 4: // Button
  964.             case 5: // Check box
  965.             case 7: // Control
  966.                 sSize = *(short *) hPtr;
  967.                 hPtr += sizeof(short);
  968.                 SetControlValue((ControlHandle) iHandle, *(short *) hPtr);
  969.                 hPtr += sSize;
  970.                 pseudoItem++;
  971.                 break;
  972.             case 6: // Radio Button
  973.                 if (tSize = GetRadioMPDSize(radio, pane, i - (*dataH)->baseItems + 1)) {
  974.                     sSize = *(short *) hPtr;
  975.                     hPtr += sizeof(short);
  976.                     SetControlValue((ControlHandle) iHandle, *(short *) hPtr);
  977.                     hPtr += sSize;
  978.                     pseudoItem++;
  979.                 }
  980.                 break;
  981.             case editText:
  982.                 sSize = *(short *) hPtr;
  983.                 hPtr += sizeof(short);
  984. #ifdef INC_TOO_MUCH
  985.                 hPtr += CallEditActionProc((*dataH)->EditAction, 
  986.                         kT2PAction, hPtr, iHandle, pane, pseudoItem);
  987. #else
  988.                 CallEditActionProc((*dataH)->EditAction, 
  989.                         kT2PAction, hPtr, iHandle, pane, pseudoItem);
  990. #endif
  991.                 if (!hilited) {
  992.                     SelectDialogItemText(dlog, i, 0, 32768);
  993.                     hilited = true;
  994.                 }
  995.                 hPtr += sSize;
  996.                 pseudoItem++;
  997.                 break;
  998.             default:
  999.                 break;
  1000.         }
  1001.         CallClickActionProc((*dataH)->ClickAction, kInitAction, dlog, pane, i);
  1002.     }
  1003.     hPtr += DoGroupAction(kT2PAction, dlog, hPtr, pane, &pseudoItem);
  1004.     HUnlock((*dataH)->theData);
  1005.     return true;
  1006. }
  1007.  
  1008. short HandleRadioGroup(DialogPtr dlog, short item)
  1009. {
  1010.     MPDHdl dataH;
  1011.     RadioGroupPtr group;
  1012.     short i, pane;
  1013.     short ret = kNotHandled;
  1014.  
  1015.     dataH = (MPDHdl) GetWRefCon(dlog);
  1016.     pane = (*dataH)->currentPane;
  1017.     
  1018.     // Return kHandled if the control was in a radio group,
  1019.     // otherwise return kNotHandled
  1020.     for(group=(*dataH)->radio; group; group=group->next) {
  1021.         if (group->pane != pane) continue;
  1022.         for(i=0; i<group->num; i++) {
  1023.             // We allow a radio control to be a member of more than one group.
  1024.             if (group->items[i] == item) {
  1025.                 ret = kHandled;
  1026.                 ToggleGroup(dlog, group, item);
  1027.             }
  1028.         }
  1029.     }
  1030.     return ret;
  1031. }
  1032.  
  1033. short DoGroupAction(short mType, DialogPtr dlog, Ptr hPtr, short pane, short *item)
  1034. {
  1035.     short ret = 0, val;
  1036.     MPDHdl dataH;
  1037.     RadioGroupPtr group;
  1038.  
  1039.     switch (mType) {
  1040.         case kP2TAction:
  1041.             dataH = (MPDHdl) GetWRefCon(dlog);
  1042.             break;
  1043.         case kT2PAction:
  1044.             dataH = (MPDHdl) GetWRefCon(dlog);
  1045.             break;
  1046.         case kCalcAction:
  1047.         case kInitAction:
  1048.             dataH = (MPDHdl) dlog;
  1049.             dlog = NULL;
  1050.             break;
  1051.         default:
  1052.             return kNotHandled;
  1053.     }
  1054.     
  1055.     for(group=(*dataH)->radio; group; group=group->next) {
  1056.         if (group->pane == pane) {
  1057.             val = CallGroupActionProc((*dataH)->GroupAction, 
  1058.                     mType, group, (Handle) dataH, dlog, hPtr, pane, *item);
  1059.             if (item) {
  1060.                 (*item)++;
  1061.                 hPtr += val;
  1062.             }
  1063.             ret += val;
  1064.         }
  1065.     }
  1066.     return ret;
  1067. }
  1068.  
  1069. /********************************************************************************
  1070.  *
  1071.  * Default Action Procedures
  1072.  *
  1073.  ********************************************************************************/
  1074.  
  1075. void DefaultAction(Ptr theData, short len, short iType, short pane, short item)
  1076. {
  1077.     switch (iType & 0x7f) {
  1078.         case 4: // Button
  1079.         case 5: // Check Box
  1080.         case 6: // Radio Button
  1081.         case 7: // Control
  1082.             if (len == sizeof(short)) *(short *) theData = 0;
  1083.             break;
  1084.     }
  1085. }
  1086.  
  1087. short DefaultEditAction(short mType, Ptr hPtr, Handle iHandle, short pane, short item)
  1088. {
  1089.     short ret = 0;
  1090.     Str255 textStr;
  1091.     
  1092.     switch (mType) {
  1093.         case kP2TAction:
  1094.             GetDialogItemText(iHandle, textStr);
  1095.             Pstrcpy((unsigned char *) hPtr, textStr);
  1096.             ret = 256;
  1097.             break;
  1098.         case kT2PAction:
  1099.             Pstrcpy(textStr, (unsigned char *) hPtr);
  1100.             SetDialogItemText(iHandle, textStr);
  1101.             ret = 256;
  1102.             break;
  1103.         case kCalcAction:
  1104.             ret = 256;
  1105.             break;
  1106.         case kInitAction:
  1107.             *hPtr = 0;
  1108.             break;
  1109.         default:
  1110.             break;
  1111.     }
  1112.     return ret;
  1113. }
  1114.  
  1115. short DefaultClickAction(short mType, DialogPtr dlog, short pane, short item)
  1116. {
  1117.     MPDHdl dataH;
  1118.     short iType;
  1119.     Rect iRect;
  1120.     Handle iHandle;
  1121.  
  1122.     switch (mType) {
  1123.         case kValidateAction:    // No default validation
  1124.         case kInitAction:        // No default initialization actions
  1125.             return noErr;
  1126.     }
  1127.     // mType == kClickAction
  1128.  
  1129.     dataH = (MPDHdl) GetWRefCon(dlog);
  1130.     GetDialogItem(dlog, item, &iType, &iHandle, &iRect);
  1131.     switch(iType & 0x7f) {
  1132.         case 4: // Button
  1133.             // No default action for buttons
  1134.             break;
  1135.         case 5: // Check
  1136.              ToggleCheck(dlog, item);
  1137.             break;
  1138.         case 6: // Radio
  1139.             if (!HandleRadioGroup(dlog, item - (*dataH)->baseItems + 1))
  1140.                 ToggleCheck(dlog, item);
  1141.             break;
  1142.         case 7: // CTRL
  1143.             // They handle themselves.
  1144.             break;
  1145.     }
  1146.     return noErr;
  1147. }
  1148.  
  1149. short DefaultGroupAction(short mType, RadioGroupPtr group, Handle H, DialogPtr dlog,
  1150.     Ptr hPtr, short pane, short item)
  1151. {
  1152.     short i, value, ret = 0;
  1153.     MPDHdl dataH = (MPDHdl) H;
  1154.     
  1155.     switch (mType) {
  1156.         case kP2TAction:
  1157.             hPtr += sizeof(short);
  1158.             for(i=0; i<group->num; i++) {
  1159.                 if (GetCheckOrRadio(dlog, group->items[i] + (*dataH)->baseItems - 1))
  1160.                     *(short *) hPtr = i + 1;
  1161.             }
  1162.             ret += sizeof(short) + sizeof(short);
  1163.             break;
  1164.         case kT2PAction:
  1165.             hPtr += sizeof(short);
  1166.             for(i=0; i<group->num; i++) {
  1167.                 if (value = (*(short *) hPtr) == i + 1)
  1168.                     SetCheckOrRadioButton(dlog, group->items[i] + (*dataH)->baseItems - 1, value);
  1169.                 else SetCheckOrRadioButton(dlog, group->items[i] + (*dataH)->baseItems - 1, 0);
  1170.             }
  1171.             ret += sizeof(short) + sizeof(short);
  1172.             break;
  1173.         case kCalcAction:
  1174.             ret += sizeof(short) + sizeof(short);
  1175.             break;
  1176.         case kInitAction:
  1177.             *(short *) hPtr = sizeof(short);
  1178.             hPtr += sizeof(short);
  1179.             *(short *) hPtr = 1;
  1180.             hPtr += sizeof(short);
  1181.             ret += sizeof(short) + sizeof(short);
  1182.             break;
  1183.     }
  1184.     
  1185.     return ret;
  1186. }
  1187.  
  1188.  
  1189. /********************************************************************************
  1190.  *
  1191.  * Utility Functions
  1192.  *
  1193.  ********************************************************************************/
  1194.  
  1195.  
  1196. /* Custom dialog item which simply draws a gray box.
  1197.  * If run on a Mac without Color QuickDraw or in B&W mode, it draws a
  1198.  * stippled gray line, otherwise it draws a real gray line.
  1199.  */
  1200. pascal void DrawGray (DialogPtr theDialog, short theItem)
  1201. {
  1202.     Rect iRect;
  1203.     short iKind;
  1204.     Handle iHandle;
  1205.     RGBColor oBack, oFore, gFore;
  1206.     GrafPtr oldPort;
  1207.  
  1208.     GetPort(&oldPort);
  1209.     SetPort(theDialog);
  1210.     GetDialogItem (theDialog, theItem, &iKind, &iHandle, &iRect);
  1211.     if (gQDVersion && (*((CGrafPtr) qd.thePort)->portPixMap)->pixelSize > 1) {
  1212.         GetForeColor(&oFore);
  1213.         GetBackColor(&oBack);
  1214.         gFore = oFore;
  1215.         if (gQDVersion == 2 && GetGray(GetGDevice(), &oBack, &gFore)) {
  1216.             RGBForeColor(&gFore);
  1217.         } else {
  1218.             gFore.red = (oFore.red + oBack.red) / 2;
  1219.             gFore.green = (oFore.green + oBack.green) / 2;
  1220.             gFore.blue = (oFore.blue + oBack.blue) / 2;
  1221.             RGBForeColor(&gFore);
  1222.         }
  1223.     } else {
  1224. #ifdef __MWERKS__
  1225.         PenPat(&qd.gray);
  1226. #else
  1227.         PenPat(qd.gray);
  1228. #endif
  1229.     }
  1230.     
  1231.     // Actuall draw the line. We really draw a box, so one could use this code
  1232.     // for doing other things.
  1233.     FrameRect(&iRect);
  1234.     
  1235.     // Put things back the way it was.
  1236.     if (gQDVersion && (*((CGrafPtr) qd.thePort)->portPixMap)->pixelSize > 1) {
  1237.         RGBForeColor(&oFore);
  1238.         RGBBackColor(&oBack);
  1239.     } else {
  1240. #ifdef __MWERKS__
  1241.         PenPat(&qd.black);
  1242. #else
  1243.         PenPat(qd.black);
  1244. #endif
  1245.     }
  1246.     SetPort(oldPort);
  1247. }
  1248.  
  1249. #if USESROUTINEDESCRIPTORS
  1250. RoutineDescriptor gGrayRoutine = BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, DrawGray);
  1251. UniversalProcPtr gGrayProc = &gGrayRoutine;
  1252. #else
  1253. UniversalProcPtr gGrayProc = (UniversalProcPtr) DrawGray;
  1254. #endif
  1255.  
  1256. /* Sets a dialog user item to be a gray box.
  1257.  * Uses UPPs for native PowerPC support.
  1258.  */
  1259. void SetItemToGray(DialogPtr dlog, short item)
  1260. {
  1261.     Handle iHandle;
  1262.     short iKind;
  1263.     Rect iRect;
  1264.     
  1265.     GetDialogItem (dlog, item, &iKind, &iHandle, &iRect);
  1266.     SetDialogItem(dlog, item, iKind, (Handle) gGrayProc, &iRect);
  1267. }
  1268.  
  1269. /* Hilite a dialog item.
  1270.  */
  1271. void    HiliteItem(DialogPtr dlgPtr, short itemNo, short state)
  1272. {
  1273.     short    iKind;
  1274.     Handle    iHandle;
  1275.     Rect    iRect;
  1276.  
  1277.     GetDialogItem(dlgPtr, itemNo, &iKind, &iHandle, &iRect);
  1278.     HiliteControl((ControlHandle) iHandle, state);
  1279. }
  1280.  
  1281. /* Enable or disable a menu item.
  1282.  */
  1283. void AbleDisItem(short menu, short item, short flag)
  1284. {
  1285.     MenuHandle theMenu = GetMenuHandle(menu);
  1286.     
  1287.     if (!theMenu) return;
  1288.     
  1289.     if (flag)
  1290.         EnableItem(theMenu, item);
  1291.     else
  1292.         DisableItem(theMenu, item);
  1293. }
  1294.  
  1295. /* Draw a Grow Icon in a window without those silly lines.
  1296.  */
  1297. void MyDrawGrow(WindowPtr win)
  1298. {
  1299.     RgnHandle curClip, rgn;
  1300.     Rect rct;
  1301.     
  1302.     if (rgn = NewRgn()) {
  1303.         rct = win->portRect;
  1304.         rct.left = rct.right - 15;
  1305.         rct.top = rct.bottom - 15;
  1306.         curClip = NewRgn();
  1307.         GetClip(curClip);
  1308.         RectRgn(rgn,&rct);
  1309.         SetClip(rgn);
  1310.         DrawGrowIcon(win);
  1311.         SetClip(curClip);
  1312.         DisposeRgn(curClip);
  1313.         DisposeRgn(rgn);
  1314.     }
  1315. }
  1316.  
  1317. /* Get the item handle for a dialog item.
  1318.  */
  1319. ControlHandle GetItemHandle(DialogPtr theDialog, short item)
  1320. {
  1321.     ControlHandle iHandle;
  1322.     Rect iRect;
  1323.     short iType;
  1324.     
  1325.     GetDialogItem(theDialog,item,&iType,(Handle *) &iHandle,&iRect);
  1326.     return iHandle;
  1327. }
  1328.  
  1329. /* Specialized version of KeyEquivFilter (in Uilities.c) to read the
  1330.  *   key equivalent string from a different item number (theItem) and
  1331.  *   to add an offset to the activated item, to allow DITL-local
  1332.  *   item numbering in the key equivalent string.
  1333.  */
  1334. pascal Boolean    keyAltFilter(DialogPtr dlg, short theItem, short offset, EventRecord *event, short *item)
  1335. {
  1336.     short    itemType;
  1337.     Handle    itemHndl;
  1338.     Rect    itemRect;
  1339.     Str255    itemText;
  1340.     short    i, theChr, theMod, equivChr, modMask, modVal, itemNum;
  1341.     long    tick;
  1342.  
  1343.     if (event->what == updateEvt) {
  1344.         if (dlg == (DialogPtr)event->message) OutlineDialogItem(dlg, 1);
  1345.         return(false);
  1346.     }
  1347.  
  1348.     if (event->what != keyDown) return(false);
  1349.  
  1350.     itemNum = 0;
  1351.  
  1352.     theChr = event->message   & charCodeMask;
  1353.     theMod = event->modifiers & keyCodeMask;
  1354.  
  1355.     if ((theChr == 0x0D) || (theChr == 0x03)) {        /* If return or enter... */
  1356.         if (!(theMod & (cmdKey + optionKey + controlKey))) itemNum = 1;
  1357.     }        
  1358.     else {
  1359.  
  1360.         GetDialogItem(dlg, theItem, &itemType, &itemHndl, &itemRect);
  1361.         GetDialogItemText(itemHndl, itemText);
  1362.  
  1363.         for (i = 1; i <= *itemText; i += 9) {
  1364.             equivChr = GetHexByte((char *)(itemText + i));
  1365.             modMask  = GetHexByte((char *)(itemText + i + 2)) << 8;
  1366.             modVal   = GetHexByte((char *)(itemText + i + 4)) << 8;
  1367.             itemNum  = GetHexByte((char *)(itemText + i + 6));
  1368.             if (theChr == equivChr)
  1369.                 if ((theMod & modMask) == modVal) break;
  1370.             itemNum = 0;
  1371.         }
  1372.     }
  1373.  
  1374.     if (itemNum) {
  1375.         itemNum += offset;
  1376.         GetDialogItem(dlg, itemNum, &itemType, &itemHndl, &itemRect);
  1377.         if ((* (ControlHandle) itemHndl)->contrlHilite == 255) return false;
  1378.         HiliteControl((ControlHandle)itemHndl, 1);
  1379.         tick = TickCount();
  1380.         while (TickCount() < tick + 10);
  1381.         HiliteControl((ControlHandle)itemHndl, 0);
  1382.         *item = itemNum;
  1383.         return(true);
  1384.     }
  1385.  
  1386.     return(false);
  1387. }
  1388.  
  1389. /* Return the value of a dialog item
  1390.  */
  1391. short GetDialogItemValue(DialogPtr dlgPtr, short itemNo)
  1392. {
  1393.     short    iKind;
  1394.     Handle    iHandle;
  1395.     Rect    iRect;
  1396.  
  1397.     GetDialogItem(dlgPtr, itemNo, &iKind, &iHandle, &iRect);
  1398.     return(GetControlValue((ControlHandle)iHandle));
  1399. }
  1400.  
  1401. /* Custom dialog centering routine which returns a color dialog port and
  1402.  * uses CenterWindow (Utilities.c) to actually center the window.
  1403.  */
  1404. DialogPtr MyGetCenteredDialog(short id, DialogPtr storage, WindowPtr relatedWindow,
  1405.     WindowPtr behind, Boolean *wasVisible)
  1406. {
  1407.     DialogTHndl        dlogResource;
  1408.     DialogPtr        dialog;
  1409.     Handle            ditl;
  1410.     char            hstate;
  1411.     OSErr            err;
  1412.     
  1413.     dialog = nil;
  1414.     *wasVisible = true;
  1415.     if (dlogResource = (DialogTHndl)GetAppResource('DLOG', id, &err)) {
  1416.         hstate = LockHandleHigh((Handle)dlogResource);
  1417.         *wasVisible = (*dlogResource)->visible;
  1418.         (*dlogResource)->visible = false;
  1419.         ditl = GetAppResource('DITL', id, &err);
  1420.         DetachResource(ditl);
  1421.         if (gQDVersion) {
  1422.             if (dialog =
  1423.                     NewColorDialog(storage, &(*dlogResource)->boundsRect,
  1424.                     (*dlogResource)->title, false, (*dlogResource)->procID,
  1425.                     behind, (*dlogResource)->goAwayFlag,
  1426.                     (*dlogResource)->refCon, ditl)) {
  1427.                 Rect sizeInfo = {0,0,0,0};
  1428.                 
  1429.                 CenterWindow(dialog, relatedWindow, sizeInfo);
  1430.             }
  1431.         } else {
  1432.             if (dialog =
  1433.                     NewDialog(storage, &(*dlogResource)->boundsRect,
  1434.                     (*dlogResource)->title, false, (*dlogResource)->procID,
  1435.                     behind, (*dlogResource)->goAwayFlag,
  1436.                     (*dlogResource)->refCon, ditl)) {
  1437.                 Rect sizeInfo = {0,0,0,0};
  1438.                 
  1439.                 CenterWindow(dialog, relatedWindow, sizeInfo);
  1440.             }
  1441.         }
  1442.         (*dlogResource)->visible = *wasVisible;
  1443.         HSetState((Handle)dlogResource, hstate);
  1444.     }
  1445.     return(dialog);
  1446. }
  1447.  
  1448. /* Copy a Pascal string
  1449.  */
  1450. void Pstrcpy(Str255 dest, ConstStr255Param src)
  1451. {
  1452.     register short i;
  1453.     
  1454.     for(i=0; i <= src[0]; i++) {
  1455.         dest[i] = src[i];
  1456.     }
  1457. }
  1458.  
  1459. /* Enable or disable a dialog item
  1460.  */
  1461. void AbleDItem(DialogPtr dlog, short item, short state)
  1462. {
  1463.     Handle iHandle;
  1464.     Rect iRect;
  1465.     short iType;
  1466.  
  1467.     GetDialogItem(dlog, item, &iType, &iHandle, &iRect);
  1468.      HiliteControl((ControlHandle) iHandle, state ? 0 : 255);
  1469. }
  1470.